From 2694545468cdcee127d2b17d9b01d51f2cd8ce6f Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 10 Feb 2015 02:50:57 +0100 Subject: [PATCH] cssnode: Add visibility concept This allows hiding nodes of invisible widgets. And that in turn makes sure :nth-child() works as expected. --- gtk/gtkcssmatcher.c | 30 +++++++++++++++++++++++++----- gtk/gtkcssnode.c | 34 +++++++++++++++++++++++++++++----- gtk/gtkcssnodeprivate.h | 5 +++++ gtk/gtkcsswidgetnode.c | 2 ++ gtk/gtkwidget.c | 4 ++++ 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/gtk/gtkcssmatcher.c b/gtk/gtkcssmatcher.c index 956271a78e..b2b5c75a53 100644 --- a/gtk/gtkcssmatcher.c +++ b/gtk/gtkcssmatcher.c @@ -256,13 +256,33 @@ gtk_css_matcher_node_get_parent (GtkCssMatcher *matcher, return gtk_css_node_init_matcher (node, matcher); } +static GtkCssNode * +get_previous_visible_sibling (GtkCssNode *node) +{ + do { + node = gtk_css_node_get_previous_sibling (node); + } while (node && !gtk_css_node_get_visible (node)); + + return node; +} + +static GtkCssNode * +get_next_visible_sibling (GtkCssNode *node) +{ + do { + node = gtk_css_node_get_next_sibling (node); + } while (node && !gtk_css_node_get_visible (node)); + + return node; +} + static gboolean gtk_css_matcher_node_get_previous (GtkCssMatcher *matcher, const GtkCssMatcher *next) { GtkCssNode *node; - node = gtk_css_node_get_previous_sibling (next->node.node); + node = get_previous_visible_sibling (next->node.node); if (node == NULL) return FALSE; @@ -340,7 +360,7 @@ gtk_css_matcher_node_nth_child (GtkCssNode *node, if (node == NULL) return FALSE; - node = gtk_css_node_get_previous_sibling (node); + node = get_previous_visible_sibling (node); } if (a == 0) @@ -352,7 +372,7 @@ gtk_css_matcher_node_nth_child (GtkCssNode *node, while (node) { b++; - node = gtk_css_node_get_previous_sibling (node); + node = get_previous_visible_sibling (node); } return b % a == 0; @@ -368,7 +388,7 @@ gtk_css_matcher_node_nth_last_child (GtkCssNode *node, if (node == NULL) return FALSE; - node = gtk_css_node_get_next_sibling (node); + node = get_next_visible_sibling (node); } if (a == 0) @@ -380,7 +400,7 @@ gtk_css_matcher_node_nth_last_child (GtkCssNode *node, while (node) { b++; - node = gtk_css_node_get_next_sibling (node); + node = get_next_visible_sibling (node); } return b % a == 0; diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c index 402aa3366d..5040ff23b1 100644 --- a/gtk/gtkcssnode.c +++ b/gtk/gtkcssnode.c @@ -44,7 +44,7 @@ gtk_css_node_set_invalid (GtkCssNode *node, if (node->parent) { - if (invalid) + if (invalid && node->visible) gtk_css_node_set_invalid (node->parent, TRUE); } else @@ -343,6 +343,8 @@ gtk_css_node_init (GtkCssNode *cssnode) cssnode->decl = gtk_css_node_declaration_new (); cssnode->style = g_object_ref (gtk_css_static_style_get_default ()); + + cssnode->visible = TRUE; } static void @@ -436,17 +438,19 @@ gtk_css_node_reposition (GtkCssNode *node, else { g_object_unref (node); - gtk_css_node_set_children_changed (node->parent); + if (node->visible) + gtk_css_node_set_children_changed (node->parent); } node->parent = parent; if (parent) { - gtk_css_node_set_children_changed (parent); + if (node->visible) + gtk_css_node_set_children_changed (parent); g_object_ref (node); - if (node->invalid) + if (node->invalid && node->visible) gtk_css_node_set_invalid (parent, TRUE); } else @@ -564,6 +568,25 @@ gtk_css_node_get_style (GtkCssNode *cssnode) return cssnode->style; } +void +gtk_css_node_set_visible (GtkCssNode *cssnode, + gboolean visible) +{ + if (cssnode->visible == visible) + return; + + cssnode->visible = visible; + + if (cssnode->parent) + gtk_css_node_set_children_changed (cssnode->parent); +} + +gboolean +gtk_css_node_get_visible (GtkCssNode *cssnode) +{ + return cssnode->visible; +} + void gtk_css_node_set_widget_type (GtkCssNode *cssnode, GType widget_type) @@ -761,7 +784,8 @@ gtk_css_node_validate (GtkCssNode *cssnode, child; child = gtk_css_node_get_next_sibling (child)) { - gtk_css_node_validate (child, timestamp, changes); + if (child->visible) + gtk_css_node_validate (child, timestamp, changes); } _gtk_bitmask_free (changes); diff --git a/gtk/gtkcssnodeprivate.h b/gtk/gtkcssnodeprivate.h index 3c6abfdb23..ea082ba9ad 100644 --- a/gtk/gtkcssnodeprivate.h +++ b/gtk/gtkcssnodeprivate.h @@ -49,6 +49,7 @@ struct _GtkCssNode GtkCssChange pending_changes; /* changes that accumulated since the style was last computed */ + guint visible :1; /* node will be skipped when validating or computing styles */ guint invalid :1; /* node or a child needs to be validated (even if just for animation) */ guint children_changed :1; /* the children changed since last validation */ }; @@ -88,6 +89,10 @@ GtkCssNode * gtk_css_node_get_last_child (GtkCssNode * GtkCssNode * gtk_css_node_get_previous_sibling(GtkCssNode *cssnode); GtkCssNode * gtk_css_node_get_next_sibling (GtkCssNode *cssnode); +void gtk_css_node_set_visible (GtkCssNode *cssnode, + gboolean visible); +gboolean gtk_css_node_get_visible (GtkCssNode *cssnode); + void gtk_css_node_set_widget_type (GtkCssNode *cssnode, GType widget_type); GType gtk_css_node_get_widget_type (GtkCssNode *cssnode); diff --git a/gtk/gtkcsswidgetnode.c b/gtk/gtkcsswidgetnode.c index 5c89a98124..d142c93e10 100644 --- a/gtk/gtkcsswidgetnode.c +++ b/gtk/gtkcsswidgetnode.c @@ -294,6 +294,8 @@ gtk_css_widget_node_new (GtkWidget *widget) result = g_object_new (GTK_TYPE_CSS_WIDGET_NODE, NULL); result->widget = widget; + gtk_css_node_set_visible (GTK_CSS_NODE (result), + gtk_widget_get_visible (widget)); return GTK_CSS_NODE (result); } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index e13145ccfe..cfb4223bfa 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4869,6 +4869,8 @@ gtk_widget_show (GtkWidget *widget) gtk_widget_queue_compute_expand (widget->priv->parent); } + gtk_css_node_set_visible (widget->priv->cssnode, TRUE); + g_signal_emit (widget, widget_signals[SHOW], 0); g_object_notify (G_OBJECT (widget), "visible"); @@ -4967,6 +4969,8 @@ gtk_widget_hide (GtkWidget *widget) gtk_widget_queue_compute_expand (widget); } + gtk_css_node_set_visible (widget->priv->cssnode, FALSE); + g_signal_emit (widget, widget_signals[HIDE], 0); if (!gtk_widget_is_toplevel (widget)) gtk_widget_queue_resize (widget); -- 2.30.2